/**
*  
* @Function 打包工具类
* @ProjectName credit-data-platform 
* @PackageName com.py.credit.utils    
* @FileName ZipUtil.java    
* @Date 2018年10月23日下午4:31:25
* @Author Min DongXv
* @Copyright (c) 2018, 金电联行 All Rights Reserved.   
*   
*/  
package com.py.credit.utils;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.util.List;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Zip;
import org.apache.tools.ant.types.FileSet;

import com.py.credit.common.logs.ExceptionLogger;
import com.py.credit.common.rest.RestServiceResult;
import com.py.credit.entity.ZipEntity;

/**
 * 
 * @Function 打包工具类
 * @ClassName ZipUtil
 * @Date 2018年10月23日 下午4:31:25
 * @Author Min DongXv
 * 
 */
public class ZipUtil {

	private static final int ZERO = 0;

	private static final int BUFFER_SIZE = 2048;

	private static final int NEGATIVE_NUM_1 = -1;

	private static final String NO_FILE = "未读取到文件";

	private ZipUtil() {
	}

	/**
	 *
	 * @Function 使用ant进行对文件路径下的文件打包，压缩包已存在直接返回压缩包(简单模式，无子文件夹打包)
	 * @FileName ZipUtil.java
	 * @MethodName zipByAnt
	 * @param zipPath
	 *            压缩包存放路径
	 * @param zipName
	 *            压缩包名称
	 * @param 文件路径(最后带斜杠)
	 * @param include
	 *            包含的文件(例如:*.pdf)
	 * @param exclude
	 *            剔除的文件(例如:*.pdf)
	 * @Author Min DongXv
	 *
	 */
	public static RestServiceResult<String> zipByAnt(String zipPath, String zipName, String filesPath, String include,
			String exclude) {
		RestServiceResult<String> result = new RestServiceResult<>();
		String fullPath = zipPath + zipName;
		try {
			File zipFile = new File(fullPath);
			if (zipFile.exists()) {
				result.setData(fullPath);
				return result;
			}
			File srcdir = new File(filesPath);
			if (srcdir.exists()) {
				Project project = new Project();
				Zip zip = new Zip();
				zip.setProject(project);
				zip.setDestFile(zipFile);
				FileSet fileSet = new FileSet();
				fileSet.setProject(project);
				if (srcdir.isDirectory()) {
					// 传入文件目录
					fileSet.setDir(srcdir);
					// 有指定包含文件
					if (StringUtils.isNotBlank(include)) {
						fileSet.setIncludes(include);
					}
					// 有指定剔除文件
					if (StringUtils.isNotBlank(exclude)) {
						fileSet.setExcludes(exclude);
					}
				} else {
					// 传入文件
					fileSet.setFile(srcdir);
				}
				zip.addFileset(fileSet);
				zip.execute();
				result.setData(fullPath);
				return result;
			} else {
				result.setCode(RestServiceResult.CODE_UNKNOW);
				result.setMsg(NO_FILE);
				return result;
			}
		} catch (Exception e) {
			result.setCode(RestServiceResult.CODE_UNKNOW);
			result.setMsg("文件打包异常！");
			return result;
		}
	}

	/**
	 *
	 * @Function 使用ant进行压缩包更新(简单模式，无子文件夹打包)
	 * @FileName ZipUtil.java
	 * @MethodName zipUpdateByAnt
	 * @param zipPath
	 *            压缩包存放路径
	 * @param zipName
	 *            压缩包名称
	 * @param filePath
	 *            文件路径(带后缀)
	 * @Author Min DongXv
	 *
	 */
	public static RestServiceResult<String> zipUpdateByAnt(String zipPath, String zipName, String filePath) {
		RestServiceResult<String> result = new RestServiceResult<>();
		String fullPath = zipPath + zipName;
		try {
			File zipFile = new File(fullPath);
			File srcdir = new File(filePath);
			if (srcdir.exists()) {
				Project project = new Project();
				Zip zip = new Zip();
				zip.setProject(project);
				zip.setDestFile(zipFile);
				// 压缩包存在文件会更新
				zip.setUpdate(true);
				FileSet fileSet = new FileSet();
				fileSet.setProject(project);
				if (srcdir.isDirectory()) {
					result.setCode(RestServiceResult.CODE_UNKNOW);
					result.setMsg(NO_FILE);
					return result;
				} else {
					// 传入文件
					fileSet.setFile(srcdir);
				}
				zip.addFileset(fileSet);
				zip.execute();
				result.setData(fullPath);
				return result;
			} else {
				result.setCode(RestServiceResult.CODE_UNKNOW);
				result.setMsg(NO_FILE);
				return result;
			}
		} catch (Exception e) {
			result.setCode(RestServiceResult.CODE_UNKNOW);
			result.setMsg("文件打包异常！");
			return result;
		}
	}


	/**
	 *
	 * @Function 文件打成压缩包
	 * @FileName ZipUtil.java
	 * @MethodName zip
	 * @param filePaths
	 *            文件路径集合
	 * @Author Min DongXv
	 *
	 */
	public static RestServiceResult<String> zip(List<ZipEntity> filePaths) {
		RestServiceResult<String> result = new RestServiceResult<>();
		File zipFile = new File(UUID.randomUUID().toString() + DateUtils.getCurrentTimeNumber());
		InputStream is = null;
		BufferedInputStream bs = null;
		try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile))) {
			for (ZipEntity e : filePaths) {
				// 压缩包实体
				ZipEntry entry = new ZipEntry(e.getFileName());
				zipOut.putNextEntry(entry);
				is = new FileInputStream(e.getFilePath() + e.getFileName());
				// 缓冲区
				bs = new BufferedInputStream(is, BUFFER_SIZE);
				byte[] buffer = new byte[BUFFER_SIZE];
				int readLen;
				// 读写
				while ((readLen = bs.read(buffer, ZERO, BUFFER_SIZE)) != NEGATIVE_NUM_1) {
					zipOut.write(buffer, ZERO, readLen);
				}
				zipOut.closeEntry();
			}
		} catch (Exception e) {
			ExceptionLogger.error("ZipUtil#zip", "打包异常!ERROR:" + e.getMessage(), e);
			result.setCode(RestServiceResult.CODE_UNKNOW);
			result.setMsg("文件打包异常");
			return result;
		} finally {
			try {
				if (null != is) {
					is.close();
				}
				if (null != bs) {
					bs.close();
				}
			} catch (IOException e) {
				ExceptionLogger.error("ZipUtil#zip", "打包流关闭异常!ERROR:" + e.getMessage(), e);
			}
		}
		result.setData(zipFile.getAbsolutePath());
		return result;
	}

	/**
	 *
	 * @Function 压缩包文件下载
	 * @FileName ZipUtil.java
	 * @MethodName zipDownload
	 * @param zipName
	 *            压缩包名称
	 * @param zipFile
	 *            压缩包文件
	 * @Author Min DongXv
	 *
	 */
	public static RestServiceResult<Object> zipDownload(String zipName, HttpServletResponse response, String zipPath) {
		RestServiceResult<Object> result = new RestServiceResult<>();
		byte[] buffer = new byte[BUFFER_SIZE];
		File zipFile = new File(zipPath);
		// 下载
		try (FileInputStream zipInput = new FileInputStream(zipFile); OutputStream out = response.getOutputStream()) {
			response.setContentType("application/octet-stream");
			response.addHeader("Content-Disposition",
					"attachment; filename=" + URLEncoder.encode(zipName, "UTF-8") + ".zip");
			int len;
			while ((len = zipInput.read(buffer)) != NEGATIVE_NUM_1) {
				out.write(buffer, ZERO, len);
			}
		} catch (Exception e) {
			ExceptionLogger.error("ZipUtil#zipDownload", "下载异常", e);
			result.setCode(RestServiceResult.CODE_UNKNOW);
			result.setMsg("文件下载异常");
			return result;
		} finally {
			// 删除压缩包
			try {
				Files.delete(zipFile.toPath());
			} catch (IOException e) {
				ExceptionLogger.error("ZipUtil#zipDownload", "删除压缩包失败", e);
			}
		}
		return result;
	}


	/**
	 *
	 * @Function 压缩包生成下载
	 * @FileName ZipUtil.java
	 * @MethodName zipCreateDownLoad
	 * @param zipName
	 *            压缩包名称
	 * @param zipFile
	 *            压缩包文件
	 * @param filePaths
	 *            文件路径集合
	 * @Author Min DongXv
	 *
	 */
	public static RestServiceResult<Object> zipCreateDownLoad(List<ZipEntity> filePaths, String zipName, HttpServletResponse response) {
		RestServiceResult<Object> result = new RestServiceResult<>();
		RestServiceResult<String> zipResult = zip(filePaths);
		if (RestServiceResult.CODE_UNKNOW == zipResult.getCode()) {
			result.setCode(RestServiceResult.CODE_UNKNOW);
			result.setMsg(zipResult.getMsg());
			return  result;
		}
		return zipDownload(zipName, response, String.valueOf(result.getData()));
	}
}
